package com.dankegongyu.screenrecord;

import android.annotation.TargetApi;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.projection.MediaProjection;
import android.os.Binder;
import android.os.Build;
import android.os.Environment;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;

import androidx.annotation.Nullable;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;

import com.dankegongyu.testscreenrecord.R;

import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

/**
 * 描述：录屏服务
 * 作者：ChaoZheng on 2019-12-17 02:15
 * 邮箱：chaozheng@dankegongyu.com
 * <p>
 * 源码：https://github.com/KitChenZhou/apk/tree/32a7cfe5e9f3079f381cdb882c31309663f93e0f
 */

public class ScreenRecordService extends Service {
    /* 工作线程*/
    private HandlerThread mRecordWorkThread;
    private static Handler sRecordHandler;
    /* 计时器*/
    private TimerRunnable mTimerRunnable;

    /* 录屏引擎 */
    private ScreenRecordEngine mRecordEngine;

    /* 录屏浮窗 */
    private WinViewUtil mWinUtil;
    View.OnClickListener mWinListener = null;
    private View mWinView;

    private RecorderControllerImpl mRecorderController;
    /* 录屏通知id*/
    private int ID_NOTI_RECORD = 1;

    private List<IOnRecorderStateChangeCallback> mCallbacks;

    @Nullable
    @Override //多个Activity进行绑定，只会第一次绑定调用一次，其他的直接获取第一次绑定返回的值
    public IBinder onBind(Intent intent) {
        if (mRecorderController == null) {
            mRecorderController = new RecorderControllerImpl(this);
        }
        return mRecorderController;
    }

    @Override
    public void onCreate() {
        if (TextUtils.isEmpty(ScreenRecordConfig.Contants.OUTPUT_FILE_DIR_DEFAULT)) {
            ScreenRecordConfig.Contants.OUTPUT_FILE_DIR_DEFAULT = getExternalFilesDir(Environment.DIRECTORY_MOVIES).getAbsolutePath();
        }
        super.onCreate();
        // 初始化录屏准备工作
        initRecordWorks();
        // 初始化浮窗
        initWinToast();
        initReceiver();
    }

    StopRecordReceiver mStopRecordReceiver = new StopRecordReceiver();
    public static final String ACTION_STOP_RECORD = "stopRecord";

    public class StopRecordReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            stopRecord();
        }
    }

    private void initReceiver() {
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(ACTION_STOP_RECORD);
        LocalBroadcastManager.getInstance(this).registerReceiver(mStopRecordReceiver, intentFilter);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // 如果返回 START_STICKY 是说服务应该一直运行除非我们手动停止它
        return START_STICKY;
    }

    /**
     * 初始化录屏相关工作，工作线程、录屏引擎及回调等
     */
    private void initRecordWorks() {
        // 工作线程
        mRecordWorkThread = new HandlerThread("record_work_thread");
        mRecordWorkThread.start();
        sRecordHandler = new Handler(mRecordWorkThread.getLooper());

        mRecordEngine = new ScreenRecordEngine();
        mCallbacks = new ArrayList<>();
    }

    /**
     * 初始化录屏浮窗
     * <br/> 只有当应用处于后台时，才显示浮窗
     */
    private void initWinToast() {
        if (ScreenRecordConfig.Contants.WIN_IMG) {
            mWinView = LayoutInflater.from(this).inflate(R.layout.layout_record_window_toast_img, null);
            mWinUtil = new WinViewUtil.Builder(this).setCustomView(mWinView, dp2px(52f), dp2px(52f)).create();
        } else {
            mWinView = LayoutInflater.from(this).inflate(R.layout.layout_record_window_toast, null);
            mWinUtil = new WinViewUtil.Builder(this).setCustomView(mWinView).create();
        }
        /* 点击计时浮窗后打开main活动 */
        mWinListener = new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (null != ScreenRecordConfig.stopRecordListener) {
                    ScreenRecordConfig.stopRecordListener.onClick();
                    return;
                }
                stopRecord();
            }
        };
        mWinUtil.getRootView().setOnClickListener(mWinListener);
    }

    /**
     * dp转px
     *
     * @param dpValue dp值
     * @return px值
     */
    public int dp2px(final float dpValue) {
        final float scale = getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }


    //    @Override
    //    public int onStartCommand(Intent intent, int flags, int startId) {
    //        // 如果返回 START_STICKY 是说服务应该一直运行除非我们手动停止它
    //        return START_STICKY;
    //    }

    /**
     * 开始录制
     */
    private void startRecord() {
        // 开始录屏
        mRecordEngine.startRecord();

        // 计时
        if (mTimerRunnable == null)
            mTimerRunnable = new TimerRunnable();
        mTimerRunnable.reset();
        sRecordHandler.post(mTimerRunnable);
        // 回调onRecordStart
        callOnRecordStart();

        mWinUtil.show();
        LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(new Intent(PermissionActivity.ACTION_FINISH_ACTIVITY));
    }


    /**
     * 结束录制,释放资源
     *
     * @return 成功返回 true
     */
    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    private boolean stopRecord() {
        if (null != sRecordHandler) {
            sRecordHandler.removeCallbacksAndMessages(null);
        }
        if (!mRecordEngine.stopRecord()) {
            callOnRecordStop(true);
            return false;
        }
        mWinUtil.dismiss();
        // 回调onRecordStop
        callOnRecordStop(false);

        stopSelf();

        return true;
    }

    /**
     * 调用所有注册的回调的onRecordStart方法
     */
    private void callOnRecordStart() {
        if (mCallbacks != null && mCallbacks.size() > 0) {
            for (IOnRecorderStateChangeCallback callback : mCallbacks) {
                callback.onRecordStart();
            }
        }
    }

    /**
     * 调用所有注册的回调的callOnRecordStop方法
     */
    private void callOnRecordStop(boolean error) {
        if (mCallbacks != null && mCallbacks.size() > 0) {
            for (IOnRecorderStateChangeCallback callback : mCallbacks) {
                callback.onRecordStop(error);
            }
        }
    }

    /**
     * 启动录屏服务
     * <p>
     * <br/> call this method in user-define Application
     *
     * @param context 上下文
     */
    public static void start(Context context) {
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) { // 大于5.0支持录屏
            // 启动服务
            context.startService(new Intent(context, ScreenRecordService.class));
        }
    }

    /**
     * 停止服务
     *
     * @param context
     */
    public static void stop(Context context) {
        context.stopService(new Intent(context, ScreenRecordService.class));
    }

    private boolean winImgSwitchFlag;

    /**
     * 计时与通知发送工作
     */
    private class TimerRunnable implements Runnable {
        private int counter = 0;

        @Override
        public void run() {
            if (mRecordEngine.isRecording()) {
                if (ScreenRecordConfig.Contants.WIN_IMG) {
                    winImgSwitchFlag = !winImgSwitchFlag;
                    mWinUtil.setImgBg(mWinView, R.id.iv_gif, getResources().getDrawable(winImgSwitchFlag ? R.drawable.git_record_toast_win_1 : R.drawable.git_record_toast_win_0));
                } else {
                    String time = getStringTime(counter);
                    ++counter;
                    // 发通知
                    // 回调录屏更新
                    if (mCallbacks != null && mCallbacks.size() > 0) {
                        for (IOnRecorderStateChangeCallback callback : mCallbacks) {
                            callback.onRecordUpdate(time);
                        }
                    }
                    // 设置浮窗文字
                    mWinUtil.setTextViewText(mWinView, R.id.id_tv_record_win_toast, time);
                }

                sRecordHandler.postDelayed(this, 1000);  // 每一秒刷新下通知
            }
        }

        public void reset() {
            counter = 0;
        }
    }

    /**
     * 将数字转化为时间显示
     *
     * @param count 秒数
     * @return 时间字符串表示
     */
    private String getStringTime(int count) {
        int hour = count / 3600;
        int min = count % 3600 / 60;
        int second = count % 60;
        return String.format(Locale.CHINA, "%02d:%02d:%02d", hour, min, second);
    }

    /**
     * 添加状态改变回调
     *
     * @param callback {@link IOnRecorderStateChangeCallback}
     */
    void addOnRecorderStateChangeCallback(IOnRecorderStateChangeCallback callback) {
        if (callback != null && !mCallbacks.contains(callback)) {
            mCallbacks.add(callback);
        }
    }

    /**
     * 移除回调
     *
     * @param callback {@link IOnRecorderStateChangeCallback}
     */
    public void removeRecordingCallback(IOnRecorderStateChangeCallback callback) {
        if (mCallbacks.contains(callback)) {
            mCallbacks.remove(callback);
        }
    }

    /**
     * 移除所有回调
     */
    private void removeAllRecordingCallbacks() {
        if (mCallbacks == null)
            return;
        for (IOnRecorderStateChangeCallback callback : mCallbacks) {
            mCallbacks.remove(callback);
        }
    }

    /**
     * 录制控制器
     */
    private class RecorderControllerImpl extends Binder implements IRecorderController {
        private ScreenRecordService service;

        public RecorderControllerImpl(ScreenRecordService service) {
            this.service = service;
        }

        @Override
        public void startRecord() {
            sRecordHandler.post(new Runnable() {
                @Override
                public void run() {
                    service.startRecord();
                }
            });
        }

        @Override
        public boolean stopRecord() {
            return service.stopRecord();
        }

        @Override
        public void setConfig(int width, int height, int dpi) {
            mRecordEngine.setConfig(width, height, dpi);
        }

        @Override
        public boolean isRecording() {
            return mRecordEngine.isRecording();
        }

        @Override
        public void setMediaProject(MediaProjection projection) {
            mRecordEngine.setMediaProjection(projection);
        }

        @Override
        public void addRecordingCallback(IOnRecorderStateChangeCallback callback) {
            service.addOnRecorderStateChangeCallback(callback);
        }

        @Override
        public void removeRecordingCallback(IOnRecorderStateChangeCallback callback) {
            service.removeRecordingCallback(callback);
        }

        public void removeAllRecordingCallbacks() {
            service.removeAllRecordingCallbacks();
        }

        @Override
        public String getStoreFileAbsolutePath() {
            return mRecordEngine.getAbsoluteFilePath();
        }

        @Override
        public String getStoreFileDir() {
            return mRecordEngine.getSavedFileDir();
        }

        public void setService(ScreenRecordService service) {
            this.service = service;
        }

    }

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
    @Override
    public void onDestroy() {
        super.onDestroy();
        // 释放录屏资源
        if (mRecordEngine != null) {
            if (mRecordEngine.isRecording())
                stopRecord();
            mRecordEngine.releaseRecorder();
            mRecordEngine = null;
        }

        // 移除控制回调
        if (mRecorderController != null) {
            mRecorderController.removeAllRecordingCallbacks();
            mRecorderController.setService(null);
            mRecorderController = null;
        }
        // 释放Handler资源
        if (sRecordHandler != null) {
            sRecordHandler.removeCallbacksAndMessages(null);
            mTimerRunnable = null;
            sRecordHandler = null;
        }

        // 释放工作线程资源
        if (mRecordWorkThread != null && mRecordWorkThread.isAlive()) {
            mRecordWorkThread.quitSafely();
            mRecordWorkThread.interrupt();
            mRecordWorkThread = null;
        }

        // 释放浮窗资源
        if (mWinUtil != null) {
            mWinUtil.clear();
            mWinUtil = null;
            mWinListener = null;
        }

        if (null != mStopRecordReceiver) {
            LocalBroadcastManager.getInstance(this).unregisterReceiver(mStopRecordReceiver);
        }

    }
}
